﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO;
using MARZ_Script.analysis;
using MARZ_Script.lexer;
using MARZ_Script.node;
using MARZ_Script.parser;
using System.Reflection;
using SableCC15.CodeGeneration;

using Microsoft.Build.Evaluation;

namespace SableCC15
{
    class Program
    {
        static int Main(string[] args)
        {
            //string temp = Directory.GetCurrentDirectory();
            CodeGenerator.FileName = "Target";
            // Stream st = new FileStream("SHIT", FileMode.Open);
            StreamReader sr;
            if (args.Length == 0)
            {
                sr = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("SableCC15.testCode.txt"));
            }
            else
            {
                Console.WriteLine("Compiling: " + args[0]);
                sr = new StreamReader(args[0]);
            }

            Start ast;
            try
            {
                Lexer lex = new Lexer(sr);

                Parser parse = new Parser(lex);

                ast = parse.Parse();
            }
            catch (ParserException pE)
            {
                Console.WriteLine(pE.Message + "\n" + pE.StackTrace);
                Console.ReadLine();
                return 1;
            }
            catch (LexerException lE)
            {
                Console.WriteLine(lE + "\n" + lE.StackTrace);
                Console.ReadLine();
                return 1;
            }
            SemanticAnalyser sa = new SemanticAnalyser();
            // SableCC15.CodeGeneration.ExpressionCodeGen ECG = new CodeGeneration.ExpressionCodeGen();
            CodeGenerator CG = new CodeGenerator();
            ast.Apply(sa);


            //Added so we can catch all errors thrown in semantic analyser in one pass
            //Problem is execution continues through the branch of the parse tree so we catch errors that aren't the users fault. 
            //Eg. if theres an error when declaring a variable, everytime that variable is used an error saying it wasnt declared will also be shown
            //Or it wont throw errors when its suppose to in that branch of the tree. eg. if theres an error in an expression some type in that expression will stil rise to the top and be used
            if (sa.ExceptionList.Count != 0)
            {
                Console.WriteLine(sa.ExceptionList.Count + " errors found:");
                for (int i = 0; i < sa.ExceptionList.Count; i++) //runs through all the errors caught under semantic analysis
                {
                    Console.WriteLine("Error:\n" + sa.ExceptionList[i].Message);

                    Console.WriteLine("_________________________");
                    Console.WriteLine();
                }
                Console.ReadLine();
                return 1; //exits with "error code" 1
            }

            //HACK TEST CODE\/
            //**********
            else
            {
                Console.WriteLine("ID\tSCOPE\tDataType|ScopeLevel");
                PrintSymbolTable(scopes.Start, sa);

                Utility.ResetFile();
                ast.Apply(CG);
                //http://stackoverflow.com/questions/9942499/building-programatically-a-project
                string path = Path.GetFullPath(Assembly.GetExecutingAssembly().Location);
                path = Directory.GetParent(path).ToString();
                path = Directory.GetParent(path).ToString();
                path = Directory.GetParent(path).ToString();
                path = Directory.GetParent(path).ToString();
                Project p = new Project(path + @"\MarzFramework\MarzFramework.csproj");

                if (!p.Build())
                    Console.WriteLine("\nERROR in c# compilation");
                else
                {
                    System.Diagnostics.Process.Start(path + @"\MarzFramework\bin\Debug\MarzFramework.exe");
                    Console.WriteLine("\nCompile successful");
                }
                Console.ReadLine();
            }
            
            return 0; //exits normally
        }

        static void PrintSymbolTable(scopes scope, SemanticAnalyser sa)
        {
            foreach (string se in sa.SymbolTable.Symbols.Keys)
            {
                string[] seIdAndScope = se.Split(',');
                VariableEntry ve = (VariableEntry)sa.SymbolTable.Symbols[se];

                Console.WriteLine(seIdAndScope[0] + "\t" + seIdAndScope[1] + "\t" + ve.DataType + "|" + ve.ScopeLevel);

            }
        }
    }
}
